﻿// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using Coding4Fun.Chair.Cockpit.Controls;
using Coding4Fun.Chair.Kinect;
using Coding4Fun.Chair.Robot;
using Coding4Fun.Kinect.Wpf.Controls;

namespace Coding4Fun.Chair.Cockpit
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		bool _doesMotorHavePower;
		readonly bool _allowedToDrive = Properties.Settings.Default.IsMotorEnabled;
        		
		readonly INuiSensor _sensor = new DepthCamera();
		readonly MediaElement _horn = new MediaElement(); 

        //Motor controllers
        Jellybean _hardware;
		
		public MainWindow()
		{
			InitializeComponent();

            Loaded += MainWindow_Loaded;
            Closing += MainWindow_Closing;

            uxReclineButton.Click += uxReclineButton_Click;
            uxPowerButton.Click += uxPowerButton_Click;
            uxHornButton.Click += uxHornButton_Click;
		}

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
			_sensor.FrameReady -= sensor_FrameReady;
			_sensor.Stop();
        }

		/// <summary>
		/// Various testing code to demonstrate design capabilities.
		/// </summary>
		void MainWindow_Loaded(object sender, RoutedEventArgs e)
		{
			MessagePrompt.Show("Starting Kinect");

            InitHornSound();

            _hardware = new Jellybean(
                Properties.Settings.Default.LeftSerialPort,
                    Properties.Settings.Default.RightSerialPort,
                    _allowedToDrive)
            {
                AllowedMovementArea = Properties.Settings.Default.AllowedMovementArea,
                MaxThrottle = Properties.Settings.Default.MaxThrottle
            };

            _sensor.FrameReady += sensor_FrameReady;

			Dispatcher.BeginInvoke((Action)(() =>
			                                	{
			                                		_sensor.Start(uxRGBSource.ActualWidth);
			                                		MessagePrompt.Hide();
			                                	}));
		}

		private void InitHornSound()
		{
			_horn.Volume = 100;
			_horn.LoadedBehavior = MediaState.Manual;
			_horn.UnloadedBehavior = MediaState.Manual;
            _horn.Source = new Uri("Resources/Carhorn.mp3", UriKind.Relative);
		}

        private static void SetReticule(Reticule ret, FrameworkElement thumb, Point hand, Point rgbOffset)
        {
			var adjustedX = hand.X - thumb.ActualWidth / 2;
			var adjustedY = hand.Y - thumb.ActualHeight / 2;

			Utilities.SetMargin(thumb, adjustedX, adjustedY);

            var retOffset = ret.PointToScreen(new Point());

            ret.Position = new Point
            {
				X = (hand.X + rgbOffset.X) - retOffset.X,
				Y = (hand.Y + rgbOffset.Y) - retOffset.Y
            };
        }

        void sensor_FrameReady(object sender, FrameReadyEventArgs e)
        {
            uxDepthMapImage.Source = e.DepthBitmap;
            uxRGBSource.Source = e.ImageBitmap;
			//uxRGBSource.Source = e.DepthBitmap;

            var margin = uxRGBSource.PointToScreen(new Point());
            
            SetReticule(uxRightReticule, uxRightControlStick, e.RightHand, margin);
            SetReticule(uxLeftReticule, uxLeftControlStick, e.LeftHand, margin);

            var rightY = uxRightReticule.GetRelativeY();
            var rightX = uxRightReticule.GetRelativeX();
            var leftY = uxLeftReticule.GetRelativeY();
            var leftX = uxLeftReticule.GetRelativeX();

            var speed = _hardware.CalculateSpeed(leftY, leftX, rightY, rightX);

            CheckButton(uxReclineButton, uxRightControlStick);
            CheckButton(uxPowerButton, uxRightControlStick);
            CheckButton(uxHornButton, uxRightControlStick);

            DisplaySpeedometer(speed);
            CalculateCompass(leftX, leftY, rightX, rightY);
            DisplayNumbers(e.LeftHand, e.RightHand, speed);

            if (_allowedToDrive && _doesMotorHavePower)
            {
                _hardware.Drive(speed);
            }
        }

        void uxPowerButton_Click(object sender, RoutedEventArgs e)
        {
            TogglePower();
        }

        void uxReclineButton_Click(object sender, RoutedEventArgs e)
        {
            ToggleRecline();
        }

        void uxHornButton_Click(object sender, RoutedEventArgs e)
        {
            _horn.Position = TimeSpan.Zero;
            _horn.Play();
        }

	    private void DisplaySpeedometer(Speed speed)
        {
            //see which is greater, X or Y and set as speed
            uxSpeedometer.Value = (Math.Abs(speed.LeftMotorFront) + 
                Math.Abs(speed.LeftMotorBack) +
                Math.Abs(speed.RightMotorFront) +
                Math.Abs(speed.RightMotorBack)) / 4d;
        }

        private void DisplayNumbers(Point leftPoint, Point rightPoint, Speed speed)
        {
            uxNumericStreamLeft.SetValue(0, Math.Round(leftPoint.X));
            uxNumericStreamLeft.SetValue(1, Math.Round(leftPoint.Y));
            uxNumericStreamLeft.SetValue(2, Math.Round(leftPoint.X));
            uxNumericStreamLeft.SetValue(3, Math.Round(leftPoint.Y));

            uxNumericStreamRight.SetValue(0, Math.Round(rightPoint.X));
            uxNumericStreamRight.SetValue(1, Math.Round(rightPoint.Y));
            uxNumericStreamRight.SetValue(2, Math.Round(rightPoint.X));
            uxNumericStreamRight.SetValue(3, Math.Round(rightPoint.Y));

            uxWheelPowerMeterLeftFront.Power = speed.LeftMotorFront;
            uxWheelPowerMeterRightFront.Power = speed.RightMotorFront;

            uxWheelPowerMeterLeftBack.Power = speed.LeftMotorBack;
            uxWheelPowerMeterRightBack.Power = speed.RightMotorBack;
        }
		
        private void ToggleRecline()
        {
            _hardware.ToggleFootrest();
        }

        
        private void TogglePower()
        {
            _doesMotorHavePower = !_doesMotorHavePower;

            _hardware.IsMotorEnabled = _allowedToDrive && _doesMotorHavePower; 
        }

        private static void CheckButton(HoverButton button, ControlStick thumbStick)
        {
            if (Utilities.IsItemMidpointInContainer(button, thumbStick))
            {
                button.Hovering();
            }
            else
            {
                button.Release();
            }
        }

        private void CalculateCompass(double x1, double y1, double x2, double y2)
        {
            var totalX = x1 + x2;
            var totalY = (y1 + y2) * -1;
            
            uxCompass.Value = Utilities.ConvertToDegrees(totalX, totalY);
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                //case Key.A:
                //    Utilities.SetMargin(uxRightControlStick, uxRightControlStick.Margin.Left - 75, uxRightControlStick.Margin.Top);
                //    break;
                //case Key.D:
                //    Utilities.SetMargin(uxRightControlStick, uxRightControlStick.Margin.Left + 75, uxRightControlStick.Margin.Top);
                //    break;
                //case Key.S:
                //    Utilities.SetMargin(uxRightControlStick, uxRightControlStick.Margin.Left, uxRightControlStick.Margin.Top + 75);
                //    break;
                //case Key.W:
                //    Utilities.SetMargin(uxRightControlStick, uxRightControlStick.Margin.Left, uxRightControlStick.Margin.Top - 75);
                //    break;
                case Key.Escape:
                    TogglePower(); 
                    break; 
                default:
                    break;
            }

			//WpfPoint current = new WpfPoint()
			//{
			//    X = uxRightControlStick.Margin.Left,
			//    Y = uxRightControlStick.Margin.Top
			//};

            //var margin = uxRGBSource.PointToScreen(new Point());

            //SetReticule(uxRightReticule, uxRightControlStick, e.RightHand, margin);
            //SetReticule(uxLeftReticule, uxLeftControlStick, e.LeftHand, margin);
        }
	}
}